#include "iap.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "flash.h"

typedef  void (*iapfun)(void);
static u32 totalFileSize = 0;
static u8  flash_buf[1024] = {0};
static uint32_t JumpAddress;
iapfun jump2app;

void iap_jump_app(void){
	uint32_t Cnt;
	__disable_irq();
	for(Cnt = 0; Cnt < Int143_IRQn; Cnt++){
		enIrqResign(Cnt);
	}
	__enable_irq();
	jump2app=(iapfun)*(vu32*)(APPLICATION_ADDR+4);
	__set_MSP(*(vu32*)APPLICATION_ADDR);
	jump2app();
}

void showFlashInfo(u32 addr,u32 size){
	u8 i = 0;
	for(i=0;i<size/FLASH_1K_SIZE;i++){
		F460FLASH_Read(APPLICATION_ADDR + i*FLASH_1K_SIZE,flash_buf,FLASH_1K_SIZE);
	}
	if(size%FLASH_1K_SIZE){
		F460FLASH_Read(APPLICATION_ADDR + i*FLASH_1K_SIZE,flash_buf,size%FLASH_1K_SIZE);
	}
}

static void iap_update_flag_clear(void){
	u8 update_flag_str[8] = {0};
	memset(update_flag_str,0,8);
	F460FLASH_Write(DOWNLOAD_FILEINFO_ADDR,flash_buf,8);
}

static bool iap_update_check(void){
	u8 update_flag_str[8] = {0};
	memset(update_flag_str,0,8);	
	F460FLASH_Read(DOWNLOAD_FILEINFO_ADDR,update_flag_str,8);
	if(update_flag_str[4]=='T'&&update_flag_str[5]=='R'&&update_flag_str[6]=='U'&&update_flag_str[7]=='E'){
		totalFileSize = update_flag_str[3]&0xff;
		totalFileSize <<= 8;
		totalFileSize |= update_flag_str[2];
		totalFileSize <<= 8;
		totalFileSize |= update_flag_str[1];
		totalFileSize <<= 8;
		totalFileSize |= update_flag_str[0];
		return true;
	}else{
		return false;
	}
	return false;
}

static void iap_write_bin(void){
	F460FLASH_Sector_Erase(APPLICATION_ADDR,totalFileSize);
	u16 i=0;
	u16 j = 0;
	u16 packetNum = totalFileSize/FLASH_1K_SIZE;
	for(i=0;i<packetNum;i++){
		F460FLASH_Read(DOWNLOAD_ADDR + i*FLASH_1K_SIZE,flash_buf,FLASH_1K_SIZE);
		F460FLASH_Write1(APPLICATION_ADDR + i*FLASH_1K_SIZE,flash_buf,FLASH_1K_SIZE);
	}
	if(totalFileSize%FLASH_1K_SIZE > 0){
		F460FLASH_Read(DOWNLOAD_ADDR + i*FLASH_1K_SIZE,flash_buf,totalFileSize%FLASH_1K_SIZE);
		F460FLASH_Write1(APPLICATION_ADDR + i*FLASH_1K_SIZE,flash_buf,totalFileSize%FLASH_1K_SIZE);
	}
	iap_update_flag_clear();
}

void iap_upgrade(void){
	if(iap_update_check() == true){
		iap_write_bin();
	}
}